from functools import wraps

from jwt import decode, ExpiredSignature
from aiomysql import DictCursor


async def select_user(mysql, member_id):
    async with mysql.acquire() as conn:
        async with conn.cursor(DictCursor) as cur:
            await cur.execute(
                f"""
SELECT
  access_token,
  resource_owner,
  member_id
FROM
  alibb.`alibb_market_user`
WHERE member_id = "{member_id}"
""")
            result = await cur.fetchone()

    if not result:
        raise TypeError("用户不存在")

    return result


def authenticated_async(method):
    @wraps(method)
    async def wrapper(self, *args, **kwargs):

        jsession = self.get_cookie("JSESSION", None)

        if jsession:

            try:
                # 对jwt进行解密, 有效期10小时
                send_data = decode(jsession, self.settings['secret_key'], leeway=self.settings['jwt_expire'],
                                   options={'verify_exp': True})
                member_id = send_data['id']

                try:
                    # 从数据库中获取user并设置给_current_user
                    user = await select_user(self.application.mysql, member_id)
                    self._current_user = user
                    # 此处很关键, 包装的函数是协程对象, 必须要await来接收
                    await method(self, *args, **kwargs)
                except TypeError as e:
                    self.set_status(403)
                    return await self.finish({"error": str(e)})
                except Exception as e:
                    self.set_status(401)
                    return await self.finish({"error": str(e)})

            except ExpiredSignature:
                self.set_status(401)
                return await self.finish({"error": "用户验证过期"})

        else:
            self.set_status(401)
            await self.finish({"error": "账号验证出错"})

    return wrapper
